# !/usr/bin/env ruby
require 'rubygems'
require 'gosu'
require 'globals'
require 'player'
require 'gameobject'
require 'bullet'
require 'powerup'
require 'explosion'
require 'particle'
require 'task'
require 'results'
require 'asteroid'
require 'enemy'
require 'black_hole'
require 'comet'
require 'speedometer'
require 'pause'
include Gosu
include Globals

class GameScreen < Screen
  attr_reader :player_num, :level, :players, :game_options, :mode, :music
  attr_accessor :paused

  def initialize(game, options)
    super(game)
    @player_num = options["player_num"]
    @objects = []
    @players = []
    @tasks = []
    @speedometers = []
    @powerups = []
    @asteroids = []
    @enemies = []
    @bullet_to_player_id = {} # used for collision detection scoring
    @mode = options["mode"] # the gameplay mode, i.e. co-op, battle, etc.
    @background = game.images["comet_bckgrnd.png"]
    #@dashboard_A = game.images["../3d_renders/dashboard.png"]
    #@dashboard_B = game.images["dashboard_B.png"]
    #@player_num = player_num
    @player_blue = Player.new(game, self, :blue)
    @players << @player_blue
    @bullet_to_player_id["blue_bullet"] = @player_blue
    Speedometer.new(self, game, @player_blue)
    if @player_num > 1
      @player_red = Player.new(game, self, :red)
      @players << @player_red
      @bullet_to_player_id["red_bullet"] = @player_red
      Speedometer.new(self, game, @player_red)
    end
    if @player_num > 2
      @player_green = Player.new(game, self, :green)
      @players << @player_green
      @bullet_to_player_id["green_bullet"] = @player_green
      Speedometer.new(self, game, @player_green)
    end
    if @player_num > 3
      @player_purple = Player.new(game, self, :purple)
      @players << @player_purple
      @bullet_to_player_id["purple_bullet"] = @player_purple
      Speedometer.new(self, game, @player_purple)
    end
    @button_actions = {"Accelerate" => :accelerate, "Reverse" => :reverse,
      "Turn Left" => :turn_left, "Turn Right" => :turn_right,
      "Shoot" => :shoot }
    # to be used in check_buttons()
    
    @menu_stack = [] # holds the UIMenuDelegates

    @mocks = []
    6.times {|i| @mocks << game.sounds["mock#{i+1}_remix.ogg"] }
    @game = game
    @game_options = options
    @transitioning = false
    @paused = false
    @level = 1
    #@asteroid_image = game.images["asteroid.png"]
    @display = Font.new(game, Gosu.default_font_name, 30) # level number
    @hap_font = Font.new(game, Gosu.default_font_name, 60)
  end

  def check_buttons
    # NOTICE: when several buttons are
    # being pressed at once, the keyboard may refuse to detect
    # other buttons. I believe this happens for all keyboards in all games, 
    # not just this one. Don't know why it happens.
    @players.each do |play|
      @game.game_controls[play.controls_index].each do |action, button|
        if @game.button_down? button
          play.method(@button_actions[action]).call
        end
      end
    end

=begin # the following big fat ugly mess has been deprecated and 
      # changed into the 7 lines above. Wave your arms and shout hooray.
       
    if @game.button_down? Button::KbLeft
      @player_blue.turn_left
    end
    if @game.button_down? Button::KbRight
      @player_blue.turn_right
    end
    if @game.button_down? Button::KbUp
      @player_blue.accelerate
    end
    if @game.button_down? Button::KbDown
      @player_blue.reverse
    end
    if @game.button_down? Button::KbSpace
      @player_blue.shoot
    end
    if @game.button_down? Button::KbNumpad8
      @player_red.accelerate
    end
    if @game.button_down? Button::KbNumpad4
      @player_red.turn_left
    end
    if @game.button_down? Button::KbNumpad6
      @player_red.turn_right
    end
    if @game.button_down? Button::KbNumpad5
      @player_red.reverse
    end
    if @game.button_down? Button::KbEnter
      @player_red.shoot
    end
    if @game.button_down? @game.char_to_button_id("'")
      @player_green.turn_right
    end
    if @game.button_down? @game.char_to_button_id(";")
      @player_green.reverse
    end
    if @game.button_down? @game.char_to_button_id("l")
      @player_green.turn_left
    end
    if @game.button_down? @game.char_to_button_id("p")
      @player_green.accelerate
    end
    if @game.button_down? @game.char_to_button_id("\\")
      @player_green.shoot
    end
    if @game.button_down? @game.char_to_button_id("s")
      @player_purple.accelerate
    end
    if @game.button_down? @game.char_to_button_id("z")
      @player_purple.turn_left
    end
    if @game.button_down? @game.char_to_button_id("c")
      @player_purple.turn_right
    end
    if @game.button_down? @game.char_to_button_id("x")
      @player_purple.reverse
    end
    if @game.button_down? Button::KbLeftShift
      @player_purple.shoot
    end
=end
  end
 
  def update
    @menu_stack.last.update unless @menu_stack.empty?
    return if @paused
    check_buttons
    @objects.reject! { |obj| !obj.update }
    @tasks.reject! { |task| !task.tick }
    @powerups.reject! { |p| p.obtained }
    @speedometers.reject! {|speed| !speed.update}
    if @game_options["mode"] == :co_op
      co_op_update
    else
      battle_update
    end
    check_collision
  end

##### Check for collision-------------------------------------
  # quite a pain in the butt. This is a very old method, so excuse
  # its convoluted nature until I feel like revising it.
  def check_collision
    @objects.each do |obj|
      id = obj.obj_id
      case id
      when "blue_bullet", "red_bullet", "green_bullet", "purple_bullet" 
        @players.each do |play|
          if play != @bullet_to_player_id[id] and @game_options["mode"] != :co_op  and !play.is_dead and play.check(obj.x, obj.y, 25, :opponent) then 
            player_score(@bullet_to_player_id[id], :player)
            obj.vanish
          end
        end
        @asteroids.each do |oid|
          if oid.check(obj.x, obj.y, 27) 
            player_score(@bullet_to_player_id[id], :asteroid)
            obj.vanish
          end
        end
        @enemies.each do |enemy|
          if enemy.check(obj.x, obj.y, 30) 
            player_score(@bullet_to_player_id[id], :enemy)
            obj.vanish
          end
        end
      when :enemy_bullet
        @players.each { |player| player.check(obj.x, obj.y, 25) }
      when :blue, :red, :purple, :green 
        @players.each do |player|
          if distance(player.x, player.y, obj.x, obj.y) < 30 and player != obj
            unless obj.is_dead or player.is_dead
             player.die unless player.invincible?
             obj.die unless obj.invincible? or !player.is_dead
            end
          end
        end
      when "asteroid"
        @players.each {|player| player.check(obj.x, obj.y, 40 * obj.factor)}
        @enemies.each {|enemy| enemy.check(obj.x, obj.y, 45 * obj.factor) }
      when "powerup"
        @players.each do |player|
        obj.obtain(player) if player.check_powerup(obj.x, obj.y, 30)
        end
      when :black_hole
        @players.each do |player|
          player.check(obj.x, obj.y, 10) 
          player.vel_x *= 0.97
          player.vel_y *= 0.97
        end
        @enemies.each {|enemy| enemy.check(obj.x, obj.y, 10) }
      when :enemy
        @players.each {|player| obj.die if player.check(obj.x, obj.y, 30) and 
                                              !player.is_dead} 
      when :comet
        @players.each {|player| player.check(obj.x, obj.y, 65) }
        @asteroids.each {|oid| oid.check(obj.x, obj.y, 65 * 1.0/oid.factor) }
        @enemies.each {|enemy| enemy.check(obj.x, obj.y, 65) }
      end
    end
  end

  def button_down(id)
    if !@menu_stack.empty? # give it to the menu first
      @menu_stack.last.button_down(id)
      return
    end
    case id
    # Pause the game with Esc key
    when Button::KbEscape
      return if @game_over or @transitioning # don't pause during game over
      PauseMenu.new(@game, self)
      @paused = true
    #when Button::KbReturn # we should save this for user input availability
    #  Pause.new(@game, self)
    end
  end

  def draw
    @menu_stack.last.draw unless @menu_stack.empty?
    @background.draw(0, 0, BACKGROUND_Z)
    # change made 6/16/10 for enhanced graphics
    #@dashboard_A.draw(0, 0, DASHBOARD_Z)
    #@dashboard_B.draw(0, (HEIGHT - 71), DASHBOARD_Z) if @player_num > 2
    @objects.each { |obj| obj.draw }
    @speedometers.each {|speed| speed.draw}
    @display.draw_rel(@level_text, WIDTH/2, 20, TEXT_Z, 0.5, 0.5)
    @hap_font.draw_rel(@hap_text, WIDTH/2, HEIGHT/2, TEXT_Z, 0.5, 0.5)
    @score_text.draw_rot(WIDTH/2, HEIGHT/2, TEXT_Z, 0) if @score_text
  end

  def start_level
    @transitioning = false
    @objects = []
    @tasks = []
    @asteroids = []
    @powerups = []
    @enemies = []
    game_start
    @music.play if @game_options["music"] and @game_options['mode'] != :co_op
    @players.each do |player|
      player.vel_x = player.vel_y = player.current_speed = 0
      player.normalize
      player.deaths = 0
      add_object(player)
      warp_players
    end
  end

  def activate
    @active = true
  end

  def deactivate
    @music.stop if @music
    @active = false
  end

  def ended?
    !@active
  end

  def add_task(task)
    @tasks << task
  end

  def add_object(obj)
    @objects << obj
  end

  def add_asteroid(asteroid)
    @asteroids << asteroid
  end

  def remove_asteroid(asteroid)
    @asteroids -= [asteroid]
  end

  def add_powerup(powerup)
    @powerups << powerup
  end

  def add_speedometer(meter)
    @speedometers << meter
  end

  def remove_speedometer(meter)
    @speedometers -= [meter]
  end

  def add_enemy(enemy)
    @enemies << enemy
  end
  
  def remove_enemy(enemy)
    @enemies -= [enemy]
  end

  def push_menu(menu)
    @menu_stack << menu
  end

  def pop_menu
    @menu_stack.pop
  end

  def kill
    super
    @music.stop if @music.playing?
  end

end


#options = {"music" => true, "sound" => true, "player_num" => 4, 
#  "mode" => :co_op}
#Coop.new(:foo, options).show
